import { applyViewboxTransform } from './applyViewboxTransform';
import { svgValidTagNamesRegEx } from './constants';
import { hasInvalidAncestor } from './hasInvalidAncestor';
import { parseUseDirectives } from './parseUseDirectives';
import { ElementsParser } from './elements_parser';

const isValidSvgTag = (el) =>
  svgValidTagNamesRegEx.test(el.nodeName.replace('svg:', ''));

export const createEmptyResponse = () => ({
  objects: [],
  elements: [],
  options: {},
  allElements: [],
});

export async function parseSVGDocument( doc, reviver, { crossOrigin, signal } = {}){
  if (signal && signal.aborted) {
    console.log('`options.signal` is in `aborted` state');
    // this is an unhappy path, we dont care about speed
    return createEmptyResponse();
  }
  const documentElement = doc.documentElement;
  parseUseDirectives(doc);

  const descendants = Array.from(documentElement.getElementsByTagName('*')),
    options = {
      ...applyViewboxTransform(documentElement),
      crossOrigin,
      signal,
    };

  const elements = descendants.filter((el) => {
    applyViewboxTransform(el);
    return isValidSvgTag(el) && !hasInvalidAncestor(el); // http://www.w3.org/TR/SVG/struct.html#DefsElement
  });
  if (!elements || (elements && !elements.length)) {
    return {
      ...createEmptyResponse(),
      options,
      allElements: descendants,
    };
  }
  const localClipPaths = {};
  const loaclMasks = {}
  descendants
    .filter((el) => el.nodeName.replace('svg:', '') === 'clipPath')
    .forEach((el) => {
      const id = el.getAttribute('id');
      localClipPaths[id] = Array.from(el.getElementsByTagName('*')).filter(
        (el) => isValidSvgTag(el)
      );
    });
  descendants
    .filter((el) => el.nodeName.replace('svg:', '') === 'mask')
    .forEach((el) => {
      const id = el.getAttribute('id');
      loaclMasks[id] = Array.from(el.getElementsByTagName('*')).filter(
        (el) => isValidSvgTag(el)
      );
    });
  // Precedence of rules:   style > class > attribute
  const elementParser = new ElementsParser(
    elements,
    options,
    reviver,
    doc,
    localClipPaths,
    loaclMasks
  );

  const instances = await elementParser.parse();

  return {
    objects: instances,
    elements,
    options,
    allElements: descendants,
  };
}
